#pragma once
#define SLT_READ	false
#define SLT_WRITE	true

#include "publicextern.h"
#include "GameLog.h"

using SLT_CALL = std::function<INT64(void)>;

template<bool>
static INT64 _slt(int fds, fd_set* set, timeval* time);

template<>
static INT64 _slt<SLT_READ>(int fds, fd_set* set, timeval* time)
{
	return select(fds, set, nullptr, nullptr, time);
}

template<>
static INT64 _slt<SLT_WRITE>(int fds, fd_set* set, timeval* time)
{
	return select(fds, nullptr, set, nullptr, time);
}

template<bool type>
static INT64 _select(SOCKET fd, UINT wait, SLT_CALL& call)
{
	fd_set fdset = { 0 };
	timeval timeout = { 0, (long)wait * 1000 };
	fdset.fd_count = 1;
	fdset.fd_array[0] = fd;
	auto ret = _slt<type>(0, &fdset, &timeout);
	return ret > 0 ? call() : ret;
}

template<bool type>
static INT64 _select(SOCKET fd, UINT wait, char* data, INT len)
{
	fd_set fdset = { 0 };
	timeval timeout = { 0, (long)wait * 1000 };
	fdset.fd_count = 1;
	fdset.fd_array[0] = fd;
	auto ret = _slt<type>(0, &fdset, &timeout);
	//WriteToLog(g_pStreamCoreLog, __FILE__, __LINE__, LOG_LEVEL_ERROR, "_select:type:%d,ret:%d", type, ret);
	if (ret > 0)
	{
		int nRes = recv(fd, data, len, 0);

		//WriteToLog(g_pStreamCoreLog, __FILE__, __LINE__, LOG_LEVEL_ERROR, "_select:recv:%d", nRes);

		return nRes;

	}
	return ret;
}

static INT _read_recursion_(SOCKET st, BYTE* rhs, UINT total, INT offset, UINT timeout = 500)
{
	do
	{
		//SLT_CALL recv_call = std::bind(recv, st, (char*)rhs + offset, (INT)total - offset, 0);
		//auto ret = _select<SLT_READ>(st, timeout, recv_call);


		//WriteToLog(g_pStreamCoreLog, __FILE__, __LINE__, LOG_LEVEL_INFO, "_read_recursion_:total:%d,offset:%d", total, offset);

		auto ret = _select<SLT_READ>(st, timeout, (char*)rhs + offset, (INT)total - offset);

		//WriteToLog(g_pStreamCoreLog, __FILE__, __LINE__, LOG_LEVEL_INFO, "_read_recursion_recv:%d,error:%d", ret, WSAGetLastError());
		if (ret == 0)
		{
			//printf("_read_recursion_ time out %d!\n", 0 - offset);
			return 0 - offset;
		}
		else if (ret < 0)
		{
			WriteToLog(g_pStreamCoreLog, __FILE__, __LINE__, LOG_LEVEL_INFO, "_read_recursion:select:ret:%ld,error:%d", ret, WSAGetLastError());
			return -1;
		}
		offset += ret;
		if (offset == total)
		{
			return offset;
		}
	} while (1);
}